package com.xiaoshuidi.cloud.module.finance.service.merchant.impl;

import cn.hutool.core.date.DateUtil;
import cn.hutool.core.date.LocalDateTimeUtil;
import cn.hutool.core.util.ObjectUtil;
import com.alibaba.fastjson.JSONObject;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.xiaoshuidi.cloud.framework.common.enums.CommonStatusEnum;
import com.xiaoshuidi.cloud.framework.pay.config.PayProperties;
import com.xiaoshuidi.cloud.framework.pay.core.client.PayClient;
import com.xiaoshuidi.cloud.framework.pay.core.client.PayClientFactory;
import com.xiaoshuidi.cloud.framework.pay.core.client.PayCommonResult;
import com.xiaoshuidi.cloud.framework.pay.core.client.impl.tongshangyun.dto.EnterPriseNotifyRespDTO;
import com.xiaoshuidi.cloud.framework.pay.core.client.impl.tongshangyun.dto.EnterpriseAccountEstablishReqDTO;
import com.xiaoshuidi.cloud.framework.pay.core.client.impl.tongshangyun.dto.EnterpriseAccountEstablishRespDTO;
import com.xiaoshuidi.cloud.module.finance.controller.admin.merchant.vo.merchant.PayMerchantCreateReqVO;
import com.xiaoshuidi.cloud.module.finance.controller.admin.merchant.vo.merchant.PayMerchantExportReqVO;
import com.xiaoshuidi.cloud.module.finance.controller.admin.merchant.vo.merchant.PayMerchantPageReqVO;
import com.xiaoshuidi.cloud.module.finance.controller.admin.merchant.vo.merchant.PayMerchantRespVO;
import com.xiaoshuidi.cloud.module.finance.controller.admin.merchant.vo.merchant.PayMerchantUpdateReqVO;
import com.xiaoshuidi.cloud.module.finance.convert.merchant.PayMerchantConvert;
import com.xiaoshuidi.cloud.module.finance.dal.dataobject.merchant.PayMerchantDO;
import com.xiaoshuidi.cloud.module.finance.dal.mysql.merchant.PayAppMapper;
import com.xiaoshuidi.cloud.module.finance.dal.mysql.merchant.PayMerchantMapper;
import com.xiaoshuidi.cloud.framework.common.pojo.PageResult;
import com.google.common.annotations.VisibleForTesting;
import com.xiaoshuidi.cloud.module.finance.enums.merchant.ReviewStatusEnum;
import com.xiaoshuidi.cloud.module.finance.service.merchant.PayMerchantService;
import com.xiaoshuidi.cloud.module.system.api.apartment.ApartmentManageApi;
import com.xiaoshuidi.cloud.module.system.enums.apartment.ApartmentManageEnum;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.BeanUtils;
import org.springframework.stereotype.Service;
import org.springframework.util.ObjectUtils;
import org.springframework.validation.annotation.Validated;

import javax.annotation.Resource;
import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;
import java.util.Collection;
import java.util.List;
import java.util.stream.Collectors;

import static com.xiaoshuidi.cloud.framework.common.exception.util.ServiceExceptionUtil.exception;
import static com.xiaoshuidi.cloud.module.finance.enums.ErrorCodeConstants.*;

/**
 * 支付商户信息 Service 实现类
 *
 * @author aquan
 */
@Service
@Validated
@Slf4j
public class PayMerchantServiceImpl implements PayMerchantService {

    @Resource
    private PayMerchantMapper merchantMapper;

    @Resource
    private PayAppMapper appMapper;

    @Resource
    private PayClientFactory payClientFactory;

    @Resource
    private PayProperties payProperties;

    @Resource
    private ApartmentManageApi apartmentManageApi;

    @Override
    public EnterpriseAccountEstablishRespDTO createMerchant(PayMerchantCreateReqVO createReqVO) {
        EnterpriseAccountEstablishRespDTO data = new EnterpriseAccountEstablishRespDTO();
        //查看此商户是否已经开户成功
        PayMerchantDO payMerchantDO = merchantMapper.getMerchantByAppartmentAndNo(createReqVO);
        if (!ObjectUtils.isEmpty(payMerchantDO)) {
            if (payMerchantDO.getReviewStatus().intValue() == ReviewStatusEnum.SUCCESS.getCode().intValue()) {
                throw exception(ENTERPRISE_ACCOUNT_ESTABLISH_REPEAT);

            } else {
                if (LocalDateTime.now().isBefore(payMerchantDO.getLinkValidTime())) {
                    data.setRegInviteLinkEndTime(LocalDateTimeUtil.format(payMerchantDO.getLinkValidTime(), DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss")))
                            .setUserId(payMerchantDO.getThirdId())
                            .setBizUserId(payMerchantDO.getId().toString())
                            .setRegInviteLink(payMerchantDO.getLinkAddress());
                    return data;
                } else {
                    EnterpriseAccountEstablishReqDTO reqDTO = new EnterpriseAccountEstablishReqDTO().setBizUserId(payMerchantDO.getId().toString())
                            .setCompanyName(payMerchantDO.getName());
                    data = getEnterpriseAccountEstablishRespDTO(reqDTO);
                    //更新本地表的third_id字段
                    merchantMapper.updateById(new PayMerchantDO().setId(payMerchantDO.getId()).setThirdId(data.getUserId())
                            .setLinkValidTime(LocalDateTimeUtil.parse(data.getRegInviteLinkEndTime(), DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss")))
                            .setLinkAddress(data.getRegInviteLink()));
                }
                return data;
            }
        } else {
            // 插入
            PayMerchantDO merchant = PayMerchantConvert.INSTANCE.convert(createReqVO);
            merchant.setReviewStatus(1);
            merchantMapper.insert(merchant);
            // H5
            EnterpriseAccountEstablishReqDTO reqDTO = new EnterpriseAccountEstablishReqDTO().setBizUserId(merchant.getId().toString())
                    .setCompanyName(merchant.getName())
                    .setAccountNo(merchant.getBankCardNo());
            data = getEnterpriseAccountEstablishRespDTO(reqDTO);

            //更新本地表的third_id字段
            merchantMapper.updateById(new PayMerchantDO().setId(merchant.getId()).setThirdId(data.getUserId())
                    .setLinkValidTime(LocalDateTimeUtil.parse(data.getRegInviteLinkEndTime(), DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss")))
                    .setLinkAddress(data.getRegInviteLink()));

            apartmentManageApi.updateApartment(merchant.getApartmentId(), ApartmentManageEnum.SHAREPROFITS_CONFIG.getCode());
            // 返回
            return data;
        }
    }

    private EnterpriseAccountEstablishRespDTO getEnterpriseAccountEstablishRespDTO(EnterpriseAccountEstablishReqDTO reqDTO) {
        //todo
        EnterpriseAccountEstablishRespDTO data = null;
        try {
            reqDTO.setJumpUrl(payProperties.getTongshangyunFrontNotifyUrl())
                    .setBackUrl(payProperties.getTongshangyunNotifyUrl() + "/" + payProperties.getChannelId());
            log.info("请求通商云企业会员开户H5，请求参数：{}", JSONObject.toJSONString(reqDTO));
            //todo 这里写死
            PayClient client = payClientFactory.getPayClient(payProperties.getChannelId());
            PayCommonResult<EnterpriseAccountEstablishRespDTO> result = client.establishEnterpriseAccount(reqDTO);
            log.info("请求企业会员开户H5，返回参数：{}", JSONObject.toJSONString(result));
            if (result.isSuccess()) {
                data = result.getData();
            }
        } catch (Exception e) {
            log.error("通商云企业会员开户H5出错{}", e.getMessage());
            throw exception(ENTERPRISE_ACCOUNT_ESTABLISH_ERROR);
        }
        return data;
    }

    @Override
    public void updateMerchant(PayMerchantUpdateReqVO updateReqVO) {
        // 校验存在
        this.validateMerchantExists(updateReqVO.getId());
        // 更新
        PayMerchantDO updateObj = PayMerchantConvert.INSTANCE.convert(updateReqVO);
        merchantMapper.updateById(updateObj);
    }

    @Override
    public void deleteMerchant(Long id) {
        // 校验
        this.validateMerchantExists(id);
        this.validateAppExists(id);
        // 删除
        merchantMapper.deleteById(id);
    }

    @Override
    public PayMerchantDO getMerchant(Long id) {
        return merchantMapper.selectById(id);
    }

    @Override
    public List<PayMerchantDO> getMerchantList(Collection<Long> ids) {
        return merchantMapper.selectBatchIds(ids);
    }

    @Override
    public PageResult<PayMerchantDO> getMerchantPage(PayMerchantPageReqVO pageReqVO) {
        return merchantMapper.selectPage(pageReqVO);
    }

    @Override
    public List<PayMerchantDO> getMerchantList(PayMerchantExportReqVO exportReqVO) {
        return merchantMapper.selectList(exportReqVO);
    }

    @Override
    public void updateMerchantStatus(Long id, Integer status) {
        // 校验商户存在
        this.checkMerchantExists(id);
        // 更新状态
        PayMerchantDO merchant = new PayMerchantDO();
        merchant.setId(id);
        merchant.setStatus(status);
        merchantMapper.updateById(merchant);
    }

    @Override
    public List<PayMerchantDO> getMerchantListByName(String merchantName) {
        return this.merchantMapper.getMerchantListByName(merchantName);
    }

    @Override
    public EnterpriseAccountEstablishRespDTO reCreateMerchant(Long id) {
        PayMerchantDO payMerchantDO = this.merchantMapper.selectById(id);
        if (ObjectUtils.isEmpty(payMerchantDO)) {
            throw exception(MERCHANT_NOT_EXIST);
        }
        EnterpriseAccountEstablishReqDTO reqDTO = new EnterpriseAccountEstablishReqDTO().setBizUserId(id.toString())
                .setCompanyName(payMerchantDO.getName());
        EnterpriseAccountEstablishRespDTO data = getEnterpriseAccountEstablishRespDTO(reqDTO);
        return data;
    }

    @Override
    public List<PayMerchantRespVO> getMerchantByAppartmentId(Long appartmentId) {
        LambdaQueryWrapper<PayMerchantDO> wrapper = new LambdaQueryWrapper<PayMerchantDO>()
                .eq(PayMerchantDO::getApartmentId, appartmentId)
                .eq(PayMerchantDO::getStatus, CommonStatusEnum.ENABLE.getStatus())
                .eq(PayMerchantDO::getReviewStatus,ReviewStatusEnum.SUCCESS.getCode());
        List<PayMerchantDO> list = this.merchantMapper.selectList(wrapper);
        List<PayMerchantRespVO> result = list.stream().map(m -> {
            PayMerchantRespVO vo = new PayMerchantRespVO();
            BeanUtils.copyProperties(m, vo);
            return vo;
        }).collect(Collectors.toList());
        return result;
    }

    @Override
    public void notifyMerchant(String userId, PayMerchantDO payMerchantDO) {
//        PayMerchantDO payMerchantDO = new PayMerchantDO();
//        BeanUtils.copyProperties(result, payMerchantDO);
//        payMerchantDO.setName(result.getCompanyName())
//                .setReviewStatus(result.getStatus())
//                .setAddress(result.getCompanyAddress())
//                //状态被覆盖
//                .setStatus(CommonStatusEnum.ENABLE.getStatus());
        merchantMapper.updateByThirdNo(userId, payMerchantDO);
    }

    @Override
    public List<PayMerchantDO> getAllMerchantList() {
        LambdaQueryWrapper<PayMerchantDO> wrapper = new LambdaQueryWrapper<PayMerchantDO>()
                .eq(PayMerchantDO::getStatus, CommonStatusEnum.ENABLE.getStatus());
        return merchantMapper.selectList(wrapper);
    }

    @VisibleForTesting
    public void checkMerchantExists(Long id) {
        if (id == null) {
            return;
        }
        PayMerchantDO merchant = merchantMapper.selectById(id);
        if (merchant == null) {
            throw exception(PAY_MERCHANT_NOT_EXISTS);
        }
    }

    /**
     * 校验商户是否存在
     *
     * @param id 商户 ID
     */
    private void validateMerchantExists(Long id) {
        if (ObjectUtil.isNull(merchantMapper.selectById(id))) {
            throw exception(PAY_MERCHANT_NOT_EXISTS);
        }
    }

    /**
     * 校验商户是否还存在支付应用
     *
     * @param id 商户ID
     */
    private void validateAppExists(Long id) {
        if (appMapper.selectCount(id) > 0) {
            throw exception(PAY_MERCHANT_EXIST_APP_CANT_DELETE);
        }
    }

    // TODO @芋艿：后续增加下合适的算法

    /**
     * 根据年月日时分秒毫秒生成商户号
     *
     * @return 商户号
     */
    private String generateMerchantNo() {
        return "M" + DateUtil.format(LocalDateTime.now(), "yyyyMMddHHmmssSSS");
    }


    @Override
    public List<PayMerchantDO> getMerchantListByApartment(Long apartmentId) {
        LambdaQueryWrapper<PayMerchantDO> wrapper = new LambdaQueryWrapper<PayMerchantDO>()
                .eq(PayMerchantDO::getApartmentId, apartmentId)
                .eq(PayMerchantDO::getStatus, CommonStatusEnum.ENABLE.getStatus());
        return merchantMapper.selectList(wrapper);
    }
}
